
#ifndef __KHAN_CLI_COMMAND_MNG_H__
#define __KHAN_CLI_COMMAND_MNG_H__

#include "khan.hpp"
#include "vty.hpp"
#include "command_manager_if.hpp"
#include "command_mode.hpp"
#include "ipc_session.hpp"
#include "cmd_db_worker.hpp"
#include "cmd_mng_session.hpp"
#include "io_service_pool.hpp"
#include "cmd_mng.hpp"  /* FIXME.. */

class command_manager;
typedef boost::shared_ptr<command_manager> command_manager_ptr;

typedef ipc_session<cmd_db_worker_ptr, command_manager>      ipc_session_t;
typedef boost::shared_ptr<ipc_session_t>        ipc_io_session_ptr;

class command_manager
: public command_agent_if,
public boost::enable_shared_from_this<command_manager>,
private boost::noncopyable       
{
public:
    typedef std::map<std::string, cmd_mode_ptr> mode_map_type;
    typedef mode_map_type::iterator   mode_map_iterator;

    static command_manager_ptr instance();

    void run()  { _ioserv_pool.run(); }
    void stop() { _ioserv_pool.stop(); }

    io_session_ptr create_session(io_service& ioserv);
    void leave(io_session_ptr participant);

	void show_agent_runcfg(vty_ptr vty);
    bool add_mode(const std::string name, const std::string prompt, bool is_auth = false)
    {
        return _cmdmng->add_mode(name, prompt, is_auth);
    }
    bool add_command( const std::string mode, const std::string cline, 
            const std::string help, ExcuteHandle function)
    {
        return _cmdmng->add_command(mode, cline, help, function);
    }

    bool add_command( const std::string mode, const std::string cmd, 
            const std::string help, const tcp_endpoint& rep,
            __u64 agent_id,  __u64 function_id);

    const std::string&    get_banner() { return _banner; };
    void  set_banner(const std::string& banner) { _banner = banner; };
    const std::string&    get_passwd() { return _passwd; }; 
    void  set_passwd(const std::string& passwd) { _passwd = passwd; };

    /* FIXME: remove this */
    bool is_exist(const std::string modestr) {   
        cmd_mode_ptr ptr;
        return _cmdmng->find_mode(modestr, ptr);
    }
    /* FIXME: remove this */
    bool is_auth(const std::string modestr) {   
        cmd_mode_ptr ptr;
        if (_cmdmng->find_mode(modestr, ptr) != true)
            return false;
        return ptr->is_auth();
    }

    const std::string prompt(const std::string modestr) {   /* FIXME */
        cmd_mode_ptr mode;
        if (!_cmdmng->find_mode(modestr, mode))
            throw std::runtime_error("mode(%s) is not exist!!");
        if (mode->is_auth()) 
            return mode->prompt();
        else 
            return _hostname +  mode->prompt() + " ";
    };

    bool describe_command(vty_ptr vty, const std::string& line, cmd_list_t& list, 
            bool child, bool& is_exec) 
    {
        return _cmdmng->describe_command(vty, line, list, child, is_exec);
    }
    bool excute_command(vty_ptr vty, const std::string& cmdline)
    {
        return _cmdmng->excute_command(vty, cmdline);
    }

private:
    /* FIXME: change agent manange mechanism !!!! */
    typedef std::map<__u64, tcp_endpoint>    agent_map_t;
    typedef std::map<io_session_ptr, cmd_db_worker_ptr> session_map;
    typedef session_map::iterator    session_map_iter;
    typedef agent_map_t::iterator    agent_map_iterator;

    command_manager();

    int handle_remote_function(__u64 agent_id, __u64 function_id, vty_ptr, 
            const std::string&, string_vector&);
    int handle_sub_remote_function(vty_ptr vty, cmd_mng_session_ptr agent);

    int handle_remote_start_dialog(cmd_mng_session_ptr agent, vty_ptr vty, string_vector& opts);
    int handle_remote_dialog_function(cmd_mng_session_ptr agent, vty_ptr vty, const std::string);

    static command_manager_ptr _instance;
    static boost::mutex    _singletone_lock;

    io_service_pool _ioserv_pool;
    int _sid;
    mode_map_type   _mode_map;
    std::string     _banner;
    std::string     _passwd;
    std::string     _hostname;
    session_map     _worker_map;
    agent_map_t     _agent_map;
    vty_ipc_msg     _ipcmsg;
    cmd_mng_ptr     _cmdmng;

    boost::mutex    _mode_lock;
    boost::mutex    _cmd_lock;
    boost::mutex    _agent_lock;
};

#endif
